package com.module.hq.engine;

import java.applet.Applet;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;

import com.dalonedrau.awt.imagesloader.ImagesLoader;
import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.GameCanvas;
import com.dalonedrau.jogl.engine.GameController;
import com.dalonedrau.jogl.engine.GameDrawable;
import com.dalonedrau.jogl.engine.GameState;
import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.Interactive;
import com.dalonedrau.jogl.engine.Interface;
import com.dalonedrau.jogl.engine.JOGLErrorHandler;
import com.dalonedrau.jogl.engine.ProjectConstants;
import com.dalonedrau.jogl.opengl.AnimationsLoader;
import com.dalonedrau.jogl.opengl.TextLoader;
import com.dalonedrau.jogl.opengl.TextureLoader;
import com.dalonedrau.jogl.opengl.ui.view.LoadingView;
import com.dalonedrau.watchable.Watchable;
import com.dalonedrau.watchable.Watcher;
import com.jogamp.opengl.util.texture.Texture;
import com.module.hq.bus.globals.HQGlobals;
import com.module.hq.view.CharacterChooserView;
import com.module.hq.view.DungeonScreenView;
import com.module.hq.view.DungeonSplashView;

public class HQController extends GameController implements Watcher {
	/** the one and only instance of the <code>GameController</code> class. */
	private static HQController	instance;
	/**
	 * Gives access to the singleton instance of {@link GameController}.
	 * @return {@link GameController}
	 */
	public static HQController getInstance() {
		if (HQController.instance == null) {
			HQController.instance = new HQController();
			GameController.setInstance(HQController.instance);
			GameState.getInstance().addWatcher(HQController.instance);
		}
		return HQController.instance;
	}
	/** the animation library. */
	private AnimationsLoader	animationLibrary;
	/** the {@link GameCanvas} instance. */
	private GameCanvas			canvas;
	/** flag indicating the game has started. */
	private boolean				gameStarted		= false;
	/** the image library. */
	private ImagesLoader		imageLibrary;
	/** flag indicating the applet has been initialized. */
	private boolean				initAppletDone	= false;
	/** the reference id of the chosen pc. */
	private int					pc;
	/** the image library. */
	private TextureLoader		textureLibrary;
	/** Hidden constructor. */
	private HQController() {
		pc = -1;
	}
	/**
	 * Gets the PC's reference id.
	 * @return <code>int</code>
	 */
	public int getPcId() {
		return pc;
	}
	/**
	 * Gets the PC's interactive object instance.
	 * @return {@link HQInteractiveObject}
	 */
	public HQInteractiveObject getPCObject() {
		HQInteractiveObject io = null;
		try {
			io = (HQInteractiveObject) Interactive.getInstance().getIO(pc);
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		return io;
	}
	/*
	 * (non-Javadoc)
	 * @see com.dalonedrau.opengl.GameController#getTexture(java.lang.String)
	 */
	@Override
	public Texture getTexture(final int id) throws Exception {
		return textureLibrary.getTexture(id);
	}
	/** Initializes the animations library. */
	@Override
	public final void initAnimations() {
		if (animationLibrary == null) {
			try {
				animationLibrary =
						new AnimationsLoader("animations.txt",
								"com/cob/dat/images/");
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
	@Override
	protected void initApplet() {
		try {
			Applet a = GameApplet.getInstance();

			a.setFocusTraversalKeysEnabled(false);
			a.setFocusTraversalKeysEnabled(false);
			a.setPreferredSize(new Dimension(
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					));
			a.setMinimumSize(new Dimension(
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					));

			// * enable double buffering
			// GLCapabilities capabilities = new GLCapabilities(null);
			GLCapabilities capabilities =
					new GLCapabilities(GLProfile.getDefault());
			capabilities.setDoubleBuffered(true);
			canvas = new GameCanvas(
					capabilities,
					GlobalConsts.SCREEN_WIDTH,
					GlobalConsts.SCREEN_HEIGHT
					);
			a.add(canvas);
			a.setVisible(true);
			initAppletDone = true;
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/** Initializes the texture library. */
	public final void initCursors() {
		if (imageLibrary == null) {
			try {
				imageLibrary =
						new ImagesLoader("cursors.txt",
								"com/cob/dat/images/");
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTHWEST_CURSOR,
						imageLibrary.getImage("cursor_north_west"));
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTH_CURSOR,
						imageLibrary.getImage("cursor_north"));
				GameDrawable.setPanCursor(GameDrawable.PAN_NORTHEAST_CURSOR,
						imageLibrary.getImage("cursor_north_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_EAST_CURSOR,
						imageLibrary.getImage("cursor_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTHEAST_CURSOR,
						imageLibrary.getImage("cursor_south_east"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTH_CURSOR,
						imageLibrary.getImage("cursor_south"));
				GameDrawable.setPanCursor(GameDrawable.PAN_SOUTHWEST_CURSOR,
						imageLibrary.getImage("cursor_south_west"));
				GameDrawable.setPanCursor(GameDrawable.PAN_WEST_CURSOR,
						imageLibrary.getImage("cursor_west"));
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void initGameData() {
		try {
			Init.getInstance().initGameData();
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void initTextureLibrary() {
		if (textureLibrary == null) {
			try {
				textureLibrary =
						new TextureLoader("images.txt",
								"com/cob/dat/images/");
				TextLoader.getInstance().setLibraryFolder(
						"com/module/bp/dat/txt/");
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
		initCursors();
	}
	/**
	 * Determines if it is the player's turn. 
	 * @return true if it is the player's turn; false otherwise
	 */
	public boolean isPlayersTurn() {
		boolean is = false;
		try {
		int ioid =
			HQScript.getInstance().getGlobalIntVariableValue(
					"ioTurn");
		is = (ioid == pc);
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		return is;
	}
	/**
	 * Loads the character chooser screen.
	 * @throws Exception if an error occurs
	 */
	public void loadCharChooser() throws Exception {
		// load screen should switch to HQ CHAR CHOOSER
		LoadingView.getInstance().setNextState(
					GameState.STATE_14HQ_CHAR_CHOOSER);
		LoadingView.getInstance().setLoadAction(
				CharacterChooserView.getInstance(),
				CharacterChooserView.getInstance().getClass().getMethod(
							"init"), new Object[] {});
		LoadingView.getInstance().setRendered(false);
		// game state goes to load screen
		GameState.getInstance().setCurrentState(
					GameState.STATE_11LOADING);
		startGame();
	}
	/**
	 * Loads the character chooser screen.
	 * @throws Exception if an error occurs
	 */
	public void loadDungeonScreen() throws Exception {
		// load screen should switch to HQ CHAR CHOOSER
		LoadingView.getInstance().setNextState(
					GameState.STATE_16HQ_DUNGEON_SCREEN);
		LoadingView.getInstance().setLoadAction(
				DungeonScreenView.getInstance(),
				DungeonScreenView.getInstance().getClass().getMethod(
							"init"), new Object[] {});
		LoadingView.getInstance().setRendered(false);
		// game state goes to load screen
		GameState.getInstance().setCurrentState(
					GameState.STATE_11LOADING);
		startGame();
	}
	/**
	 * Loads the character chooser screen.
	 * @throws Exception if an error occurs
	 */
	public void loadDungeonSplash() throws Exception {
		// load screen should switch to HQ CHAR CHOOSER
		LoadingView.getInstance().setNextState(
					GameState.STATE_15HQ_DUNGEON_SPLASH);
		LoadingView.getInstance().setLoadAction(
				DungeonSplashView.getInstance(),
				DungeonSplashView.getInstance().getClass().getMethod(
							"init"), new Object[] {});
		LoadingView.getInstance().setRendered(false);
		// game state goes to load screen
		GameState.getInstance().setCurrentState(
					GameState.STATE_11LOADING);
		startGame();
	}
	/**
	 * Loads an image file.
	 * @param fileName the file name
	 * @return {@link BufferedImage}
	 */
	public BufferedImage loadImage(final String fileName) {
		BufferedImage img = null;
		try {
			if (fileName.startsWith("com")) { // jar implementation
				System.out.println("attempting to read file " + fileName);
				InputStream is =
						getClass().getClassLoader().getResourceAsStream(
								fileName);
				System.out.println("is " + is);
				img = ImageIO.read(is);
				is.close();
				is = null;
			} else {
				File file = new File(".\\", fileName);
				if (file.exists()) {
					img = ImageIO.read(file);
				} else {
					JOGLErrorHandler.getInstance().fatalError(
							new Exception("HQController loadImage() file "
									+ fileName + " did not exist."));
				}
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
		return img;
	}
	/**
	 * Sets the chosen pc.
	 * @param refid the reference id of the chosen pc
	 */
	public void setPc(final int refid) {
		pc = refid;
	}
	/**
	 * Loads the Stormbringer character creation screen.
	 * @throws Exception if an erro occurs
	 */
	/*
	 * public void loadStormbringerCharCreator() throws Exception { // load
	 * screen should switch to STORMBINGER CHAR CREATOR
	 * LoadingView.getInstance().setNextState(
	 * GameState.STATE_13SB_CHAR_CREATOR);
	 * LoadingView.getInstance().setLoadAction( SBCharCreator.getInstance(),
	 * SBCharCreator.getInstance().getClass().getMethod( "init"), new Object[]
	 * {}); LoadingView.getInstance().setRendered(false); // game state goes to
	 * load screen GameState.getInstance().setCurrentState(
	 * GameState.STATE_11LOADING); startGame(); }
	 */
	/**
	 * Starts the game.
	 * @throws Exception if an error occurs
	 */
	public void startGame() throws Exception {}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void switchScreen() throws Exception {
		if (!initAppletDone) {
			initApplet();
		}
		// load views
		ProjectConstants.getInstance().assignViews();
		switch (GameState.getInstance().getCurrentState()) {
		case GameState.STATE_01STARTMENU:
			Interface.getInstance().setCurrentView(HQGlobals.VIEW_00_INTRO);
			break;
		case GameState.STATE_11LOADING:
			Interface.getInstance().setCurrentView(HQGlobals.VIEW_01_LOADING);
			break;
		case GameState.STATE_14HQ_CHAR_CHOOSER:
			Interface.getInstance().setCurrentView(
					HQGlobals.VIEW_02_CHARACTER_CHOOSER);
			break;
		case GameState.STATE_15HQ_DUNGEON_SPLASH:
			Interface.getInstance().setCurrentView(
					HQGlobals.VIEW_03_DUNGEON_SPLASH);
			break;
		case GameState.STATE_16HQ_DUNGEON_SCREEN:
			Interface.getInstance().setCurrentView(
					HQGlobals.VIEW_04_DUNGEON_SCREEN);
			break;
		default:
			throw new Exception("Illegal game state!! "
						+ GameState.getInstance().getCurrentState());
			/*
			 * case GameState.STATE_13SB_CHAR_CREATOR:
			 * Interface.getInstance().setCurrentView(
			 * HQGlobals.VIEW_CHAR_CREATOR_SB); break;
			 */
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void update() {
		try {
			switch (GameState.getInstance().getCurrentState()) {
			case GameState.STATE_16HQ_DUNGEON_SCREEN:
				HQTurn.getInstance().update();
				break;
			default:
				break;
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void watchUpdated(final Watchable data) {
		if (data instanceof GameState) {
			try {
				switchScreen();
			} catch (Exception ex) {
				JOGLErrorHandler.getInstance().fatalError(ex);
			}
		}
	}
}
